package com.android.camera;
import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.LiveFolders;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.Media;
import android.text.TextUtils;
import android.util.Log;

public class RephotoProvider extends ContentProvider {
	
    private static final String REPHOTO_AUTHORITY = "rephoto";

    private static final String TAG = "RephotoProvider";

    private static final String DATABASE_NAME = "rephoto.db";
    private static final int DATABASE_VERSION = 2;
    private static final String PHOTOS_TABLE_NAME = "photos";

    private static HashMap<String, String> sPhotosProjectionMap;
    private static HashMap<String, String> sLiveFolderProjectionMap;
    public static final String IS_ORIGINAL = "is_original";

    private static final int PHOTOS = 1;
    private static final int PHOTO_ID = 2;
    private static final int LIVE_FOLDER_PHOTOS = 3;

    private static final UriMatcher sUriMatcher;
    
    /**
     * This class helps open, create, and upgrade the database file.
     */
    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
        	Log.v(TAG, "onCreate called");
            db.execSQL("CREATE TABLE " + PHOTOS_TABLE_NAME + " ("
                    + Images.Media._ID + " INTEGER PRIMARY KEY,"
                    + Images.Media.DATE_TAKEN + " TEXT,"
                    + Images.Media.MIME_TYPE + " TEXT,"
                    + Images.Media.ORIENTATION + " TEXT,"
                    + Images.Media.DATA + " TEXT,"
                    + Images.Media.SIZE + " TEXT,"
                    + Images.Media.BUCKET_ID + " TEXT,"
                    + Images.Media.MINI_THUMB_MAGIC + " TEXT,"
                    + Images.Media.DATE_MODIFIED + " TEXT,"
                    + Camera.PROJECT_NAME + " TEXT,"
                    + Images.Media.TITLE + " TEXT,"
                    + Images.Media.DISPLAY_NAME+ " TEXT,"
                    + Images.Media.BUCKET_DISPLAY_NAME + " TEXT,"
                    + IS_ORIGINAL + " TEXT"
                    + ");");
        }
        
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                    + newVersion + ", which will destroy all old data");
            db.execSQL("DROP TABLE IF EXISTS photos");
            onCreate(db);
        }

    }

    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;
        switch (sUriMatcher.match(uri)) {
        case PHOTOS:
            count = db.delete(PHOTOS_TABLE_NAME, where, whereArgs);
            break;

        case PHOTO_ID:
            String photoId = uri.getPathSegments().get(1);
            count = db.delete(PHOTOS_TABLE_NAME, Images.Media._ID + "=" + photoId
                    + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
            break;

        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    @Override
    public String getType(Uri uri) {
        switch (sUriMatcher.match(uri)) {
        case PHOTOS:
        case LIVE_FOLDER_PHOTOS:
            return Images.Media.CONTENT_TYPE;

        case PHOTO_ID:
            return Images.Media.CONTENT_TYPE;

        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
    	
        Log.v(TAG, "insert( ) called with uri: "+uri);
    	
        // Validate the requested uri
        if (sUriMatcher.match(uri) != PHOTOS) {
            Log.e(TAG, "crash");
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        ContentValues values;
        if (initialValues != null) {
            values = new ContentValues(initialValues);
            Log.v(TAG, "initialValues: "+initialValues.toString());
        } else {
            values = new ContentValues();
            Log.v(TAG, "initialValues is null");
        }

        Long now = Long.valueOf(System.currentTimeMillis());

        // Make sure that the fields are all set
        if (values.containsKey(Images.Media.DISPLAY_NAME) == false) {
            values.put(Images.Media.DISPLAY_NAME, now);
        }

        if (values.containsKey(Images.Media.DATE_TAKEN) == false) {
            values.put(Images.Media.DATE_TAKEN, now);
        }
        
        if (values.containsKey(Images.Media.DATE_MODIFIED) == false) {
            values.put(Images.Media.DATE_MODIFIED, now);
        }

        if (values.containsKey(Images.Media.TITLE) == false) {
            Resources r = Resources.getSystem();
            values.put(Images.Media.TITLE, r.getString(android.R.string.untitled));
        }

        if (values.containsKey(Images.Media.MIME_TYPE) == false) {
            //XXX crash? all images need a mime type
            //values.put(Images.Media.MIME_TYPE, "");
        }
        
        if (values.containsKey(Images.Media.ORIENTATION) == false) {
            //probably OK if this isn't included
            //values.put(Images.Media.ORIENTATION, "");
        }
        
        if (values.containsKey(Images.Media.DATA) == false) {
            //XXX crash?
            //values.put(Images.Media.DATA, "");
        }
        
        if (values.containsKey(Images.Media.SIZE) == false) {
            //XXX crash?
            //values.put(Images.Media.SIZE, "");
        }
        
        if (values.containsKey(Images.Media.BUCKET_ID) == false) {
            //XXX ok to be empty?
            //values.put(Images.Media.BUCKET_ID, "");
        }
        
        if (values.containsKey(Images.Media.MINI_THUMB_MAGIC) == false) {
            //XXX ok to be empty?
            //values.put(Images.Media.MINI_THUMB_MAGIC, "");
        }
        
        if (values.containsKey(Camera.PROJECT_NAME) == false) {
            values.put(Camera.PROJECT_NAME, "<untitled>");
        }
        
        if (values.containsKey(IS_ORIGINAL) == false) {
            //XXX What would it even mean for this to be empty?
            //values.put(IS_ORIGINAL, "0");
        }

        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        long rowId = db.insert(PHOTOS_TABLE_NAME, Images.Media.DATA, values);
        if (rowId > 0) {
            //Uri noteUri = ContentUris.withAppendedId(Images.Media.EXTERNAL_CONTENT_URI, rowId);
            Uri photoUri = ContentUris.withAppendedId(ImageManager.STORAGE_URI, rowId);
            getContext().getContentResolver().notifyChange(photoUri, null);
            Log.v(TAG, "returning URI: "+photoUri);
            return photoUri;
        }

        throw new SQLException("Failed to insert row into " + uri);
    }
	
	private DatabaseHelper mOpenHelper;

	@Override
    public boolean onCreate() {
        mOpenHelper = new DatabaseHelper(getContext());
        return true;
    }

	@Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
		
		Log.v(TAG, "URI: " + uri.toString () );
		
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(PHOTOS_TABLE_NAME);

        Log.v(TAG, "Provider is trying to match: "+uri);
        
        switch (sUriMatcher.match(uri)) {
        

        case PHOTO_ID:
        	Log.v(TAG, "Case: PHOTO_ID");
            qb.setProjectionMap(sPhotosProjectionMap);
            qb.appendWhere(Images.Media._ID + "=" + uri.getPathSegments().get(1));
            break;

        case LIVE_FOLDER_PHOTOS:
        	Log.v(TAG, "Case: LIVE_FOLDER_PHOTOS");
            qb.setProjectionMap(sLiveFolderProjectionMap);
            break;
            
        case PHOTOS:
            Log.v(TAG, "Case: PHOTOS");
            qb.setProjectionMap(sPhotosProjectionMap);
            break;

        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        // If no sort order is specified use the default
        String orderBy;
        if (TextUtils.isEmpty(sortOrder)) {
            orderBy = Images.Media.DEFAULT_SORT_ORDER;
        } else {
            orderBy = sortOrder;
        }

        // Get the database and run the query
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);

        // Tell the cursor what uri to watch, so it knows when its source data changes
        Log.v(TAG, "notifcation uri for "+uri);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }

	@Override
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;
        switch (sUriMatcher.match(uri)) {
        case PHOTOS:
            count = db.update(PHOTOS_TABLE_NAME, values, where, whereArgs);
            break;

        case PHOTO_ID:
            String photoId = uri.getPathSegments().get(1);
            count = db.update(PHOTOS_TABLE_NAME, values, Images.Media._ID + "=" + photoId
                    + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
            break;

        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
	
    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(REPHOTO_AUTHORITY, "photos", PHOTOS);
        sUriMatcher.addURI(REPHOTO_AUTHORITY, "photos/#", PHOTO_ID);
        sUriMatcher.addURI(REPHOTO_AUTHORITY, "live_folders/photos", LIVE_FOLDER_PHOTOS);

        sPhotosProjectionMap = new HashMap<String, String>();
        sPhotosProjectionMap.put(Images.Media._ID, Images.Media._ID);
        sPhotosProjectionMap.put(Images.Media.DISPLAY_NAME, Images.Media.DISPLAY_NAME);
        sPhotosProjectionMap.put(Images.Media.DATE_TAKEN, Images.Media.DATE_TAKEN);
        sPhotosProjectionMap.put(Images.Media.MIME_TYPE, Images.Media.MIME_TYPE);
        sPhotosProjectionMap.put(Images.Media.ORIENTATION, Images.Media.ORIENTATION);
        sPhotosProjectionMap.put(Images.Media.DATA, Images.Media.DATA);
        sPhotosProjectionMap.put(Images.Media.SIZE, Images.Media.SIZE);
        sPhotosProjectionMap.put(Images.Media.BUCKET_ID, Images.Media.BUCKET_ID);
        sPhotosProjectionMap.put(Images.Media.MINI_THUMB_MAGIC, Images.Media.MINI_THUMB_MAGIC);
        sPhotosProjectionMap.put(Camera.PROJECT_NAME, Camera.PROJECT_NAME);
        sPhotosProjectionMap.put(Images.Media.DATE_MODIFIED, Images.Media.DATE_MODIFIED);
        sPhotosProjectionMap.put(Images.Media.DISPLAY_NAME, Images.Media.DISPLAY_NAME);
        sPhotosProjectionMap.put(Images.Media.TITLE, Images.Media.TITLE);
        sPhotosProjectionMap.put(Images.Media.BUCKET_DISPLAY_NAME, Images.Media.BUCKET_DISPLAY_NAME);
        sPhotosProjectionMap.put(IS_ORIGINAL, IS_ORIGINAL);
        
        // Support for Live Folders.
        sLiveFolderProjectionMap = new HashMap<String, String>();
        sLiveFolderProjectionMap.put(LiveFolders._ID, Images.Media._ID + " AS " +
                LiveFolders._ID);
        sLiveFolderProjectionMap.put(LiveFolders.NAME, Images.Media.TITLE + " AS " +
                LiveFolders.NAME);
        // Add more columns here for more robust Live Folders.
    }

}
